package org.jspar.io;

import java.io.IOException;
import java.io.Reader;
import java.util.HashSet;
import java.util.Set;

import org.jspar.Constants;
import org.jspar.model.AsgModule;
import org.jspar.model.Direction;
import org.jspar.model.Module;
import org.jspar.model.Net;
import org.jspar.model.NetList;
import org.jspar.model.Terminal;
import org.jspar.model.Utility;

public class IVFParser {

	private static final String MOD_START_EXP = "MX";
	private static final String MOD_PORT = "MP";
	private static final String MOD_VIEW_FLAT = "MF";
	private static final String IVF_OPEN_STR = "{";
	private static final String IVF_CLOSE_STR = "}";
	private static final String FLAT_SIG = "FS";
	private static final String FLAT_GATE = "FG";
	private static final String FLAT_PROC = "FP";
	private static final String STR_DELAY_TRANSPORT = "T";
	private static final String TRANSPORT_DELAY = null;
	private static final String INERTIAL_DELAY = null;
	private static final String FLAT_PROC_ICON_SIZE = null;
	private static final String FLAT_PROC_PIN_POSITIONS = null;

	private Reader inFile;

	private Module currentModule;
	private NetList netlist;

	private void CHK_IVF_END(String a) {
		if (a == null) {
			System.err.println("premature end to .ivf file found");
			System.exit(1);
		}
	}

	public NetList read(Reader in) throws IOException {

		inFile = in;
		
		netlist = new NetList();

		/*
		 * before we start add the predefined constant signals $0, $1
		 * and _DUMMY_SIGNAL_
		 */
		createNet("$0");
		createNet("$1");
		createNet("_DUMMY_SIGNAL_");

		/* we pick up the external port info from the hierarchy view */
		CHK_IVF_END(findToken(MOD_START_EXP));

		CHK_IVF_END(findToken(MOD_PORT));

		CHK_IVF_END(findToken(IVF_OPEN_STR));

		String token = getNextToken();
		CHK_IVF_END(token);

		/*
		 * This code counts too much on the format of ivf files. We assume triples of:
		 * "signame" "sigdir" ";" including a ";" at the end, before the closing brace.
		 */
		while (! token.equals(IVF_CLOSE_STR)) {
			String signame = token;

			token = getNextToken();
			CHK_IVF_END(token);
			String sigdir = token;

			token = getNextToken();
			CHK_IVF_END(token);

			/* check for array/bitvec busses */
			int pos;
			if ((pos = signame.indexOf('[')) < 0) {
				//netlist.add_port(signame, sigdir);
				addPort(signame, sigdir);
			} else {
				/* we have a bitvec */
				String busname = signame.substring(0, pos);
				String bus = signame.substring(pos+1, signame.length()-1);
				int high = Integer.parseInt(bus.substring(0, bus.indexOf(':')));
				int low = Integer.parseInt(bus.substring(bus.indexOf(':')+1));
				if (low <= high) {
					for (; low <= high; ++low) {
						//netlist.add_port(busname + "_" + low, sigdir);
						addPort(busname + "_" + low, sigdir);
					}
				} else
					System.err.println("bad bus spec in MP line of ivf file");
			}
			token = getNextToken();
			CHK_IVF_END(token);
		}

		/* search for the flattened view */
		token = findToken(MOD_VIEW_FLAT);

		if (token == null) {
			System.err.println(
					"error, flattened description not found in .ivf file");
			System.exit(1);
		}

		token = getNextToken();

		if (! token.equals(IVF_OPEN_STR)) {
			/* we couldn't find our open brace */
			System.err.println("error, open brace not found in .ivf file");
			System.exit(1);
		}

		/* loop through the flattened view */
		while (true) {
			token = getNextToken();
			CHK_IVF_END(token);

			if (token.equals(FLAT_SIG)) {
				/* definition of signals */
				ivf_sig_def();
			} else if (token.equals(FLAT_GATE)) {
				/* primitive gate definition */
				ivf_gate_def();
			} else if (token.equals(FLAT_PROC)) {
				/* process definition */
				ivf_proc_def();
			} else if (token.equals(IVF_CLOSE_STR)) {
				/* our closeing brace, finis */
				break;
			} else {
				/* error */
				System.err.println("illegal token, " + token
						+ ", found in flattened .ivf description");
				System.exit(1);
			}
		}
		
		return netlist;
	}

	private void addPort(String name, String dir) {
		Terminal t = null;
		Module tmod = newobject(name, dir);

		if (dir.equals("IN")) {
			t = new Terminal(tmod, name, Terminal.RIGHT, Direction.OUT, tmod.width() + 1, tmod.height() / 2);
		} else if (dir.equals("OUT")) {
			t = new Terminal(tmod, name, Terminal.LEFT, Direction.IN, -1, tmod.height() / 2);
		} else if (dir.equals("INOUT")) {
			t = new Terminal(tmod, name, Terminal.UP, Direction.INOUT, tmod.width() / 2, tmod.height() + 1);
		} else
			throw new RuntimeException("bad direction");

		tmod.addTerminal(t);

		if (t.type() == Direction.IN) {
			Utility.addpositions(tmod, 1, 0, 0);
		} else if (t.type() == Direction.OUT) {
			Utility.addpositions(tmod, 0, 0, 1);
		} 
		netlist.addExternal(t, tmod);
	}

	private boolean isDelimiter(char a) {
		return Character.isSpaceChar(a) || a == '{' || a == '}' || a == ';';
	}

	private int lastChar = -1;
	
	private int getChar() throws IOException {
		if (lastChar >= 0) {
			int c = lastChar;
			lastChar = -1;
			return c;
		}
		return inFile.read();
	}
	
	private String getNextToken() throws IOException {
		boolean done = false;
		int c;
		
		StringBuffer buffer = new StringBuffer();
		
		/* skip any white space */
		do {
			if ((c = getChar()) < 0)
				return null;
		} while (Character.isWhitespace(c));

		if (!done) {
			/* save characters until we encounter a delimiter */
			while (! isDelimiter((char) c)) {
				buffer.append((char) c);
				if ((c = getChar()) < 0)
					return null;
			}

			/* advance the pointer if we don't have a white space delimiter */
			if (!Character.isWhitespace(c)
					&& buffer.length() == 0)
				buffer.append((char) c);
			else
				lastChar = c;
		}
		return buffer.toString();
	}

	private String findToken(String expected) throws IOException {
		while (true) {
			String token = getNextToken();

			/* if we've run out of input or found the token, we are done */
			if (token == null)
				break;
			else if (expected.equals(token))
				return token;
		}
		return null;
	}

	private void ivf_sig_def() throws IOException {

		/* verify we have our open brace */
		String tok_ptr = getNextToken();
		CHK_IVF_END(tok_ptr);

		if (! tok_ptr.equals(IVF_OPEN_STR)) {
			System.err.println("found " + tok_ptr
					+ " when expecting { in .ivf file");
			System.exit(1);
		}

		for (;;) {
			tok_ptr = getNextToken();
			CHK_IVF_END(tok_ptr);

			if (tok_ptr.equals(IVF_CLOSE_STR)) {
				/* we found our terminating closing brace */
				break;
			}
			/* otherwise, add the specified signal to our string definitions */
			createNet(tok_ptr);
		}
	}

	private void ivf_gate_def() throws IOException {

		/* acquire our gate name */
		String tok_ptr = getNextToken();
		CHK_IVF_END(tok_ptr);

		/* We want the last GATE_NAME_SIZE characters to use for the name */
		String gate_name = tok_ptr; //.substring(GATE_NAME_SIZE);

		/* verify we have our open brace */
		tok_ptr = getNextToken();
		CHK_IVF_END(tok_ptr);

		if (! tok_ptr.equals(IVF_OPEN_STR)) {
			System.err.println("found " + tok_ptr
					+ " when expecting { in .ivf file");
			System.exit(1);
		}

		/* read the gate type */
		tok_ptr = getNextToken();
		CHK_IVF_END(tok_ptr);

		/* add the gate to the database */
		currentModule = newobject(gate_name, tok_ptr);

		/* read the delay time */
		tok_ptr = getNextToken();
		CHK_IVF_END(tok_ptr);

		int delayTime = checkIntegerString(tok_ptr);
		if (delayTime != 0)
			Utility.adddelay(delayTime);

		/* read the delay flag */
		tok_ptr = getNextToken();
		CHK_IVF_END(tok_ptr);
		/*if (tok_ptr.equals(STR_DELAY_TRANSPORT)) {
			// a transport delay
			currentModule.dly_type = TRANSPORT_DELAY;
		} else {
			// an inertial delay
			currentModule.dly_type = INERTIAL_DELAY;
		}*/

		/* get the number on inputs */
		tok_ptr = getNextToken();
		CHK_IVF_END(tok_ptr);

		int incount = checkIntegerString(tok_ptr);

		/* get all the inputs */
		for (int i = 0; i < incount; ++i) {
			tok_ptr = getNextToken();
			CHK_IVF_END(tok_ptr);

			/* add the input to the list of inputs for this node */
			addin(currentModule, tok_ptr, i, incount);
		}

		/* get the number on outputs */
		tok_ptr = getNextToken();
		CHK_IVF_END(tok_ptr);

		int outcount = checkIntegerString(tok_ptr);

		/* get all the outputs */
		for (int i = 0; i < outcount; ++i) {
			tok_ptr = getNextToken();
			CHK_IVF_END(tok_ptr);

			/* add the output to the list of outputs for this node */
			addout(currentModule, tok_ptr, i, outcount);
		}

		/* now that we have the counts we can tie them to the icon positions */
		Utility.addpositions(currentModule, incount, 0, outcount);

		/* get the terminating brace */
		tok_ptr = getNextToken();
		CHK_IVF_END(tok_ptr);

		if (! tok_ptr.equals(IVF_CLOSE_STR)) {
			System.err.println("illegal token, " + tok_ptr
					+ ", found expected }");
			System.exit(1);
		}
	}

	/*---------------------------------------------------------------
	 * ivf_proc_pinpositions - used to record fixed pin positions:
	 *---------------------------------------------------------------*/
	private void ivf_proc_pin_positions() throws IOException {
		int count, i, x, y;

		/* get the FPPP openning brace */
		String tok_ptr = getNextToken();
		CHK_IVF_END(tok_ptr);

		/* Read in the number of pins with fixed positions: */
		tok_ptr = getNextToken();
		CHK_IVF_END(tok_ptr);
		count = Integer.parseInt(tok_ptr);

		for (i = 0; i < count; i++) {
			/* Read in the net name: */
			String netName = new String(getNextToken());

			/* Read in the x and y coordinates: */
			tok_ptr = getNextToken();
			CHK_IVF_END(tok_ptr);
			x = Integer.parseInt(tok_ptr);

			tok_ptr = getNextToken();
			CHK_IVF_END(tok_ptr);
			y = Integer.parseInt(tok_ptr);

			/* Do something interesting with this info: */
			Utility.fix_pin_position(currentModule, netName, x, y);
		}

		/* get the FPPP terminating brace */
		tok_ptr = getNextToken();
		CHK_IVF_END(tok_ptr);
	}

	/*---------------------------------------------------------------
	 * ivf_proc_icon_size - used to record a predefined icon size
	 *---------------------------------------------------------------*/
	private void ivf_proc_icon_size() throws IOException {
		int x, y;

		/* get the FPIS openning brace */
		String tok_ptr = getNextToken();
		CHK_IVF_END(tok_ptr);

		/* Read in the x and y coordinates: */
		tok_ptr = getNextToken();
		CHK_IVF_END(tok_ptr);
		x = Integer.parseInt(tok_ptr);

		tok_ptr = getNextToken();
		CHK_IVF_END(tok_ptr);
		y = Integer.parseInt(tok_ptr);

		Utility.reset_default_icon_size(currentModule, x, y);

		/* get the FPIS terminating brace */
		tok_ptr = getNextToken();
		CHK_IVF_END(tok_ptr);
	}

	private void ivf_proc_def() throws IOException {
		int in_count = 0, inout_count = 0, out_count = 0;
		int x, y, i, tempCount, index = 0;
		//nptr ntemp;

		/* acquire our process name */
		String tok_ptr = getNextToken();
		CHK_IVF_END(tok_ptr);

		/* We want the last GATE_NAME_SIZE characters to use for the name */
		String proc_name = tok_ptr; //.substring(GATE_NAME_SIZE);

		/* verify we have our open brace */
		tok_ptr = getNextToken();
		CHK_IVF_END(tok_ptr);

		if (tok_ptr.equals(IVF_OPEN_STR)) {
			System.err.println("found " + tok_ptr
					+ " when expecting { in .ivf file");
			System.exit(1);
		}

		/* read the long process name */
		tok_ptr = getNextToken();
		CHK_IVF_END(tok_ptr);

		/* add the process to the database */
		currentModule = newobject(proc_name, tok_ptr);

		/* get the number on items on the sensitivity list */
		/* THE SENSITIVITY LIST IS IGNORED FOR NOW */
		tok_ptr = getNextToken();
		CHK_IVF_END(tok_ptr);

		inout_count = checkIntegerString(tok_ptr); /* # items on sensitivity list */

		/* flush all the items on the sensitivity list */
		for (i = 0; i < inout_count; i++) {
			tok_ptr = getNextToken();
			CHK_IVF_END(tok_ptr);

			/* add the signal to the inout list */
			Utility.addinout(tok_ptr, i, inout_count);

			/* add to a list to pull from input/output lists */
			// push(strdup(tok_ptr), &sensitivityList);
			/*
			 * // OLD only point nodes at object which are in the sensitivity list ntemp =
			 * (nptr)getnode (tok_ptr); push ((lcontents) curobj_module, (lptr *) &
			 * ntemp->in); curobj_module->oflags = PROCESS_GATE;
			 */
		}

		/*
		 * get the number of external signals, and add to inout lists
		 */
		tok_ptr = getNextToken();
		CHK_IVF_END(tok_ptr);

		tempCount = in_count = checkIntegerString(tok_ptr); /*
		 * inputs not on
		 * sensitivity list
		 */
		Set sensitivityList = new HashSet();
		/* get the signals */
		for (i = 0; i < tempCount; i++) {
			tok_ptr = getNextToken();
			CHK_IVF_END(tok_ptr);

			/* OLD: add the signal to the inout list OLD */
			/* addinout (tok_ptr, i, in_count); */

			/* Add the string to the input list: */
			if (!sensitivityList.contains(tok_ptr))
				addin(currentModule, tok_ptr, index++, in_count);
			else
				in_count--;
		}
		index = 0;

		/* get the number of output variables */
		tok_ptr = getNextToken();
		CHK_IVF_END(tok_ptr);

		tempCount = out_count = checkIntegerString(tok_ptr);/*
		 * outputs not on
		 * sensitivity list
		 */

		/* get all the variables */
		for (i = 0; i < tempCount; i++) {
			tok_ptr = getNextToken();
			CHK_IVF_END(tok_ptr);

			/* Add the string to the output list: */
			if (!sensitivityList.contains(tok_ptr))
				addout(currentModule, tok_ptr, index++, out_count);
			else
				out_count--;
		}

		/* Now look for the optional icon size info: added 3-92 (stf) */
		tok_ptr = getNextToken();
		CHK_IVF_END(tok_ptr);

		if (tok_ptr.equals(FLAT_PROC_ICON_SIZE)) {
			ivf_proc_icon_size();
			Utility.addpositions(currentModule, in_count, inout_count, out_count);

			/* get the terminating brace?? */
			tok_ptr = getNextToken();
			CHK_IVF_END(tok_ptr);

			if (tok_ptr.equals(FLAT_PROC_PIN_POSITIONS)) {
				ivf_proc_pin_positions();

				/* Now get the terminating brace: */
				tok_ptr = getNextToken();
				CHK_IVF_END(tok_ptr);
			}
		} else if (tok_ptr.equals(FLAT_PROC_PIN_POSITIONS)) {
			ivf_proc_pin_positions();

			/* Now get the terminating brace?? */
			tok_ptr = getNextToken();
			CHK_IVF_END(tok_ptr);

			if (tok_ptr.equals(FLAT_PROC_ICON_SIZE)) {
				ivf_proc_icon_size();
				/*
				 * BUG NOTE: This won't work correctly: "addpositions" will
				 * overwrite the work done in "ivf_proc_pin_positions"
				 */
				Utility.addpositions(currentModule, in_count, inout_count, out_count);

				/* Now get the terminating brace: */
				tok_ptr = getNextToken();
				CHK_IVF_END(tok_ptr);
			}
		} else {
			/* now that we have the counts we can tie them to the icon positions */
			Utility.addpositions(currentModule, in_count, inout_count, out_count);
		}

		if (tok_ptr.equals(IVF_CLOSE_STR)) {
			System.err.println("illegal token, " + tok_ptr
					+ ", found expected }");
			System.exit(1);
		}
	}

	private int checkIntegerString(String str) {
		/* verify the specified string is a valid integer string */
		try {
			return Integer.parseInt(str);
		} catch (Exception e) {
			System.err.println("illegal character found in digit string");
			return -1;
		}
	}

	/**
	 * Add2TermModule - This method is used to add a new module. This can be used in
	 * HSPICE parser to add a module.
	 * 
	 * @param name
	 *            Parser-supplied module name (e.g., CAP32)
	 * @param type
	 *            Parser-supplied identification type (e.g., CAPACITOR)
	 * @param inNode
	 *            Net name for input net
	 * @param outNode
	 *            Net name for output net
	 */
	private void Add2TermModule(String name, String type, String inNode,
			String outNode) {
		// Create a new Module( Capacitor or Resistor or Inductor or Buffer,
		// Inverter gate etc)
		currentModule = newobject(name, type);

		// Add Inputports
		Net pNet = netlist.get_net(inNode);

		// If Input Node does not exist in the global database
		if (pNet == null)
			createNet(inNode);
		addin(currentModule, inNode, 0, 1);

		// Add output ports
		pNet = netlist.get_net(outNode);

		// If output Node does not exist in the global database
		if (pNet == null)
			createNet(outNode);
		addout(currentModule, outNode, 0, 1);
	}

	/**
	 * Add3TermModule - This method is used to add a new module. This can be used in
	 * HSPICE parser to add a module.
	 * 
	 * @param name
	 *            Parser-supplied module name (e.g., CAP32)
	 * @param type
	 *            Parser-supplied identification type (e.g., CAPACITOR)
	 * @param inNode
	 *            Net name for input (left) net
	 * @param outNode
	 *            Net name for output (right) net
	 * @param inoutNode
	 *            Net name for inout (top) net
	 */

	private void Add3TermModule(String name, String type, String inNode,
			String outNode, String inoutNode) {
		// Create a new Module( Capacitor or Resistor or Inductor or Buffer,
		// Inverter gate etc)
		currentModule = newobject(name, type);

		// Add Inputports
		Net pNet = netlist.get_net(inNode);

		// If Input Node does not exist in the global database
		if (pNet == null)
			createNet(inNode);
		addin(currentModule, inNode, 0, 1);

		// Add output ports
		pNet = netlist.get_net(outNode);

		// If output Node does not exist in the global database
		if (pNet == null)
			createNet(outNode);
		addout(currentModule, outNode, 0, 1);

		// Add inout ports
		pNet = netlist.get_net(inoutNode);

		// If inout Node does not exist in the global database
		if (pNet == null)
			createNet(inoutNode);
		Utility.addinout(inoutNode, 0, 1);
	}

	/**
	 * AddNTermModule, Add a module of N terminals to the database
	 * 
	 * @param name
	 *            Parser-supplied module name (e.g., CAP32)
	 * @param type
	 *            Parser-supplied identification type (e.g., CAPACITOR)
	 * @param N
	 *            Number of nodes, followed by list of node names. followed by pairs
	 *            of char * types declaring the name of the pin (expected in the
	 *            xcircuit object) followed by the name of the net.
	 */

	/*void AddNTermModule(String name, String type, int N)
	 {
	 int i;

	 // Create a new Module( Capacitor or Resistor or Inductor or Buffer,
	 // Inverter gate etc)
	 curobj_module = Utility.newobject(name, type);  

	 for (i = 0; i < N; i++) {
	 // Add port
	 String pinName = va_arg(args  , String );
	 String netName = va_arg(args  , String );
	 INet pNet = Utility.get_net(netName);
	 
	 // If Input Node does not exist in the global database
	 if (pNet == null) {
	 Utility.newnode(netName);
	 }
	 Utility.add_xc_term(type, pinName, netName, i);
	 }
	 }*/
	
	private Module newobject(String gate_name, String gate_type) {
		Module object = new Module(gate_name, AsgModule.getModel(gate_type));
		netlist.addModule(object);
		return object;
	}
	
	private void addin(Module module, String name, int index, int noOfTerms) {
		if (name.equals(Constants.STR_DUMMY_SIGNAL)
				|| name.equals(Constants.SIG_ZERO)
				|| name.equals(Constants.SIG_ONE)
				|| name.equals(Constants.STR_GUARD_SIGNAL)) {
			add_special(module, name, index, noOfTerms, Direction.IN);
		} else
			add_in_out(module, name, index, noOfTerms, Direction.IN);
	}
	
	private void addout(Module module, String name, int index, int noOfTerms) {
		if (name.equals(Constants.STR_DUMMY_SIGNAL)
				|| name.equals(Constants.SIG_ZERO)
				|| name.equals(Constants.SIG_ONE)
				|| name.equals(Constants.STR_GUARD_SIGNAL)) {
			add_special(module, name, index, noOfTerms, Direction.OUT);
		} else
			add_in_out(module, name, index, noOfTerms, Direction.OUT);
	}

	private void add_special(Module module, String name, int index, int noOfTerms,
			Direction dir) {
		String tname = null;
		int side;
		int xPos;
		int yPos;
		Direction type = Direction.NONE;
		switch (dir.value()) {
		case Direction.IN_VALUE:
			tname = name + "_input_" + index;
			side = Terminal.LEFT;
			xPos = -1;
			yPos = Utility.relative_term_location(index, noOfTerms, module
					.height(), Constants.SPACES_PER_PIN);
			break;
		case Direction.OUT_VALUE:
			tname = name + "_output_" + index;
			side = Terminal.RIGHT;
			xPos = module.width() + 1;
			yPos = Utility.relative_term_location(index, noOfTerms, module
					.height(), Constants.SPACES_PER_PIN);
			break;
		case Direction.INOUT_VALUE:
			tname = name + "_inout_" + index;
			side = Terminal.UP;
			xPos = Utility.relative_term_location(index, noOfTerms, module
					.width(), Constants.SPACES_PER_PIN);
			yPos = module.height() + 1;
			break;

		case Direction.OUTIN_VALUE:
			tname = "inout_" + index;
			side = Terminal.DOWN;
			type = Direction.OUTIN;
			xPos = Utility.relative_term_location(index, noOfTerms, module
					.width(), Constants.SPACES_PER_PIN);
			yPos = -1;
			break;
		default:
			throw new RuntimeException(
					"add_special: terminal with bad direction " + name);
		}
		/* The TYPE is based on the signal name: */
		if (name.equals(Constants.SIG_ZERO))
			type = Direction.GND;
		else if (name.equals(Constants.SIG_ONE))
			type = Direction.VDD;

		Terminal tt = new Terminal(module, tname, side, type, xPos, yPos);
		
		if (dir == Direction.OUT)
			module.setPrimaryOut(tt);

		/* Add the terminal to the growing list of terminals for this module: */
		module.addTerminal(tt);
	}
	
	private void add_in_out(Module module, String name, int index,
			int noOfTerms, Direction dir) {
		Net tn = netlist.get_net(name);
		String tname = null;
		int side;
		int xPos;
		int yPos;

		switch (dir.value()) {
		case Direction.IN_VALUE:
			tname = "input_" + index;
			side = Terminal.LEFT;
			xPos = -1;
			yPos = Utility.relative_term_location(index, noOfTerms, module
					.height(), Constants.SPACES_PER_PIN);
			break;
		case Direction.OUT_VALUE:
			tname = "output_" + index;
			side = Terminal.RIGHT;
			xPos = module.width() + 1;
			yPos = Utility.relative_term_location(index, noOfTerms, module
					.height(), Constants.SPACES_PER_PIN);

			break;
		case Direction.INOUT_VALUE:
			tname = "inout_" + index;
			side = Terminal.UP;
			xPos = Utility.relative_term_location(index, noOfTerms, module
					.width(), Constants.SPACES_PER_PIN);
			yPos = module.height() + 1;
			break;

		case Direction.OUTIN_VALUE:
			tname = "inout_" + index;
			side = Terminal.DOWN;
			xPos = Utility.relative_term_location(index, noOfTerms, module
					.width(), Constants.SPACES_PER_PIN);
			yPos = -1;
			break;
		default:
			throw new RuntimeException(
					"add_in_out: terminal with bad direction " + name);
		}

		Terminal tt = new Terminal(module, tname, side, dir, xPos, yPos);

		if (dir == Direction.OUT)
			module.setPrimaryOut(tt);
		module.addTerminal(tt);
		tn.addTerminal(tt);
	}
	
	private void createNet(String name) {
		Net net = new Net(name);
		netlist.addNet(net);
		for (Terminal t : netlist.extTerms()) {
			if (t.name().equals(net.name())) {
				net.addTerminal(t);
				net.setType(t.isIn() ? Direction.OUT
						: t.isOut() ? Direction.IN
						: Direction.INOUT);
				return;
			}
		}
	}

}
